package lew.bing.gwalo.annotations;

import lew.bing.gwalo.semaphoreLimiter.BingoSemaphore;
import lew.bing.gwalo.semaphoreLimiter.Permits;
import lew.bing.gwalo.utils.CommonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;

/**
 * Created by 刘国兵 on 2018/7/7.
 * 如果定义了Permits的bean，则可以被拦截
 * conditionOnBean好像一直是不匹配
 */
@Aspect
@Component
public class SemaphoreHandler {

    private static final Logger logger = LoggerFactory.getLogger(SemaphoreHandler.class);

    @Autowired
    private Permits permits;


    @Around("@annotation(lew.bing.gwalo.annotations.BingoCommand)")
    public Object runWithSemaphore(ProceedingJoinPoint pjp) {
        MethodSignature pjpSignature = (MethodSignature) pjp.getSignature();
        BingoCommand command = pjpSignature.getMethod().getAnnotation(BingoCommand.class);
        // 创建key的过程
        String key = CommonUtils.getKey(pjpSignature,command.key(), pjp.getArgs());
        Semaphore semaphore = generateSemaphore(command.group(),key,command.permits());
        if (command.block()) {
            logger.debug("尝试获取信号量");
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
            logger.debug("获取成功");
        } else {
            try {
                boolean b = false;
                logger.info("尝试获取信号量");
                b = semaphore.tryAcquire();
                if (!b) {
                    throw new RuntimeException("请稍后重试");
                } else {
                    logger.debug("获取成功");
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                throw e;
            }
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        } finally {
            semaphore.release();
        }
    }




    private Semaphore generateSemaphore(String group, String key, int defaultPermits) {
        permits.changePermits(group+":"+key);
        return permits.takePermits(group,key,defaultPermits);
    }

}
